#pragma once
#include <Chronos.Agent.h>

#ifdef CHRONOS_COMMON_EVENTSTREE_EXPORT_API
#define CHRONOS_COMMON_EVENTSTREE_API __declspec(dllexport) 
#else
#define CHRONOS_COMMON_EVENTSTREE_API __declspec(dllimport) 
#endif

namespace Chronos
{
	namespace Agent
	{
		namespace Common
		{
			namespace EventsTree
			{
				#define STACK_MAX_DEPTH 32000
				#define EVENT_DEPTH_OFFSET 1
		
// ==================================================================================================================================================
				#pragma pack(push,1)
				struct CHRONOS_COMMON_EVENTSTREE_API EventEnter
				{
					__byte EventType;
					__uint Unit;
					__uint BeginTime;
				};
				#pragma pack(pop)

// ==================================================================================================================================================
				#pragma pack(push,1)
				struct CHRONOS_COMMON_EVENTSTREE_API EventLeave
				{
					__byte EventType;
					__uint EndTime;
				};
				#pragma pack(pop)

// ==================================================================================================================================================
				#pragma pack(push,1)
				struct CHRONOS_COMMON_EVENTSTREE_API MergedEvent
				{
					__byte EventType;
					__short Depth;
					__uint Unit;
					__uint Time;
					__uint Hits;
				};
				#pragma pack(pop)

// ==================================================================================================================================================
				#pragma pack(push,1)
				struct CHRONOS_COMMON_EVENTSTREE_API EventsPageHeader
				{
					EventsPageHeader();
					__bool LastPage();

					__byte PageType;
					__byte Flag;
					__uint ThreadUid;
					__uint ThreadOsId;
					__ulong EventsTreeGlobalId;
					__ushort EventsTreeLocalId;
					__int BeginLifetime;
					__int EndLifetime;
					__int PageIndex;
					__uint EventsDataSize;

					enum PageType
					{
						DetailedPageType = 0,
						MergedPageType = 1,
						FinalPageType = 2
					};

					enum PageFlag
					{
						BreakPageFlag = 0,
						ClosePageFlag = 1,
						ContinuePageFlag = 2,
					};
				};
				#pragma pack(pop)

// ==================================================================================================================================================
				#pragma pack(push,4)
				class CHRONOS_COMMON_EVENTSTREE_API DetailedEventsPage
				{
					public:
						EventsPageHeader Header;
						__byte* GetEvents();
						static void FreeEventsPage(DetailedEventsPage* eventsPage);
				};
				#pragma pack(pop)

//==================================================================================================================================================
				struct CHRONOS_COMMON_EVENTSTREE_API MergedEventContainer
				{
					MergedEventContainer()
					{
						memset(this, 0, sizeof(MergedEventContainer));
					}
					
					MergedEventContainer(EventEnter* eventEnter, __short depth)
					{
						MergedEventContainer::MergedEventContainer();
						Initialize(eventEnter);
					}

					void Initialize(EventEnter* eventEnter)
					{
						EventType = eventEnter->EventType;
						Unit = eventEnter->Unit;
					}

					void Write(MemoryStream* stream, __short depth)
					{
						MergedEvent mergedEvent;
						mergedEvent.EventType = EventType;
						mergedEvent.Depth = depth;
						mergedEvent.Unit = Unit;
						mergedEvent.Time = Time;
						mergedEvent.Hits = Hits;
						stream->Write(&mergedEvent, sizeof(MergedEvent));
						MergedEventContainer* child = ChildEventContainer;
						while (child != null)
						{
							child->Write(stream, depth + 1);
							child = child->NextEventContainer;
						}
					}
					
					__byte EventType;
					__uint Unit;
					__uint Time;
					__uint Hits;
					MergedEventContainer* NextEventContainer;
					MergedEventContainer* ChildEventContainer;
				};

// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API MergedEventsPage
				{
					public:
						MergedEventsPage(__bool isDisposable);
						~MergedEventsPage();
						void Append(DetailedEventsPage* detailedEventsPage);
						EventsPageHeader Header;
						void Save(MemoryStream* stream);
						__bool IsDisposable();
						void Reset();

					private:
						__bool EventsEquals(MergedEventContainer* eventContainer, EventEnter* eventEnter);
					private:
						__bool _isDisposable;
						Tuple<MergedEventContainer*, __uint>* _stack[STACK_MAX_DEPTH];
						MergedEventContainer* _rootEventContainer;
						DynamicBlockFactory<MergedEventContainer>* _factory;
						__short _depth;
				};

// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API EventsTreeLogger
				{
					public:
						EventsTreeLogger(GatewayClient* gatewayClient, ProfilingTimer* profilingTimer, __byte dataMarker, __uint threadUid, __uint eventsBufferSize, __ushort eventsMaxDepth);
						~EventsTreeLogger(void);
						void Enter(__byte eventType, __uint unit);
						void Leave(__byte eventType, __uint unit);
						void EnterLeave(__byte eventType, __uint unit);

					private:
						void InitializePage();
						void InitializePackage(__byte dataMarker, __uint eventsBufferSize, __uint threadUid);
						void FlushPage(__byte flag);
						void StartNewEventTree();
						void StartNewPage();
						void ResetCursor();

					private:
						ProfilingTimer* _profilingTimer;
						GatewayClient* _gatewayClient;
						__short _stackDepth;
						__bool _pageIsReady;
						__ushort _eventsMaxDepth;
						GatewayPackage* _package;
						EventsPageHeader* _eventsPageHeader;
						__byte* _eventsBufferBegin;
						__byte* _eventsBufferCursor;
						__byte* _eventsBufferEnd;
						EventEnter* _stack;

						static volatile __ulong EventTreeGlobalId;
						static volatile __short EventTreeLocalId;
				};

// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API EventsTreeLoggerCollection
				{
					public:
						EventsTreeLoggerCollection(void);
						~EventsTreeLoggerCollection(void);
						HRESULT Initialize(GatewayClient* gatewayClient, ProfilingTimer* profilingTimer, __byte dataMarker, __uint eventsBufferSize, __int eventsMaxDepth);

						EventsTreeLogger* CreateLogger(__uint osThreadId);
						EventsTreeLogger* GetLogger(__uint osThreadId);
						void DestroyLogger(__uint osThreadId);
				
						const static __guid ServiceToken;
					private:
						GatewayClient* _gatewayClient;
						__byte _dataMarker;
						ProfilingTimer* _profilingTimer;
						CriticalSection _criticalSection;
						std::map<__uint, EventsTreeLogger*>* _loggers;
						__uint _eventsBufferSize;
						__int _eventsMaxDepth;
				};
				
// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API ComplexEventsTreeMerger
				{
					public:
						ComplexEventsTreeMerger(ICallback* mergeCompletedCallback);
						~ComplexEventsTreeMerger();
						void PushPage(DetailedEventsPage* page);
						void Start();

					private:
						void MergeInternal(void* parameter);

					private:
						SingleCoreThread* _mergingThread;
						CriticalSection _pagesCriticalSection;
						InterlockedContainer<DetailedEventsPage>* _pages;
						ICallback* _mergeCompletedCallback;
						const static __uint Capacity;
				};
				
// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API SingleEventsTreeMerger
				{
					public:
						SingleEventsTreeMerger(ICallback* mergeCompletedCallback);
						~SingleEventsTreeMerger();
						void PushPage(DetailedEventsPage* page);
						void Start();
					private:
						void MergeInternal(void* parameter);
						DetailedEventsPage* GetNextPage();
						DetailedEventsPage* GetPage(__uint index);
					private:
						volatile __bool _started;
						IThread* _mergingThread;
						ICallback* _mergeCompletedCallback;
						InterlockedContainer<DetailedEventsPage>* _pages;
						volatile __uint _currentIndex;
						const static __uint Capacity;
				};

// ==================================================================================================================================================
				typedef void (__stdcall *EventsTreeMergeCompletedCallback)(__byte*, __uint);

				class CHRONOS_COMMON_EVENTSTREE_API EventsTreeMergerCollection
				{
					public:
						EventsTreeMergerCollection(EventsTreeMergeCompletedCallback mergedCompletedCallback);
						~EventsTreeMergerCollection();
						void PushPage(DetailedEventsPage* page);
					private:
						void MergeCompletedInternal(void* parameter);
						ComplexEventsTreeMerger* TakeMerger(__ushort eventsTreeLocalId);
						void CloseMerger(__ushort eventsTreeLocalId);
						void WaitWhileMerging();
					private:
						CriticalSection _criticalSection;
						SingleEventsTreeMerger* _singleMerger;
						InterlockedContainer<ComplexEventsTreeMerger>* _mergers[0xFFFF];
						EventsTreeMergeCompletedCallback _mergedCompletedCallback;
						ICallback* _mergeCompletedInternalCallback;
				};
				
// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API ProfilingTypeAdapter : public IProfilingTypeAdapter
				{
					public:
						ProfilingTypeAdapter(void);
						~ProfilingTypeAdapter(void);
						HRESULT BeginInitialize(ProfilingTypeSettings* settings);
						HRESULT ExportServices(ServiceContainer* container);
						HRESULT ImportServices(ServiceContainer* container);
						HRESULT EndInitialize();
						HRESULT SubscribeEvents();
						HRESULT FlushData();
					private:
						EventsTreeLoggerCollection* _eventsTreeLoggers;
						GatewayClient* _gatewayClient;
						__byte _dataMarker;
						ProfilingTimer* _profilingTimer;
						ProfilingTypeSettings* _settings;
				};
// ==================================================================================================================================================
				class CHRONOS_COMMON_EVENTSTREE_API DataHandler : public IDataHandler
				{
					public:
						DataHandler(EventsTreeMergeCompletedCallback callback);
						~DataHandler();
						__bool HandlePackage(__byte* data, __uint size);
					private:
						EventsTreeMergerCollection* _merger;
				};
			}
// ==================================================================================================================================================
		}
	}
}